﻿using System;
using System.Configuration;
using System.Data.SqlClient;
using FluentAssertions;
using KvDb.Tests;
using KvDb.Tests.SupportingTypes;
using KvDbApi;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace KvDb.IntegrationTests
{
    [TestClass]
    public class KeyValueWriterStreamTests
    {
        private static readonly byte[] data16K = BufferHelper.Data16K;

        [TestCategory("SQL Server Integrated Test")]
        [TestMethod]
        public void WriteThenWriteAgainForcingConcurrencyViolationThrowsExceptionButDisposesWithoutException()
        {
            var handle = new ValueHandle("testKey" + Guid.NewGuid().ToString());
            using (var c = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlKvDb"].ConnectionString))
            {
                using (var writer = new KeyValueWriterStream(c, handle))
                {
                    writer.Write(data16K, 4096 * 0, 4096);
                    writer.Write(data16K, 4096 * 1, 4096);
                    writer.Write(data16K, 4096 * 2, 4096);
                    writer.Write(data16K, 4096 * 3, 4096);
                    writer.Flush();
                }
            }

            handle.Version.HasValue.Should().BeTrue();
            handle.Version = handle.Version.Value - 1;

            using (var c = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlKvDb"].ConnectionString))
            {
                Action disposalTest = () =>
                {
                    using (var writer = new KeyValueWriterStream(c, handle))
                    {
                        writer.Write(data16K, 4096 * 0, 4096);
                        Action concurrencyViolationTest = () => writer.Flush();
                        concurrencyViolationTest.ShouldThrow<SqlException>();
                    }
                };

                disposalTest.ShouldNotThrow();
            }
        }

        [TestCategory("SQL Server Integrated Test")]
        [TestMethod]
        public void WriteThenReadRandomSerializedDataUsingWriterStream()
        {
            var handle = new ValueHandle("testKey" + Guid.NewGuid().ToString());
            using (var c = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlKvDb"].ConnectionString))
            {
                using (var writer = new KeyValueWriterStream(c, handle))
                {
                    writer.Write(data16K, 4096 * 0, 4096);
                    writer.Write(data16K, 4096 * 1, 4096);
                    writer.Write(data16K, 4096 * 2, 4096);
                    writer.Write(data16K, 4096 * 3, 4096);
                    writer.Flush();
                }

                using (var reader = new KeyValueReaderStream(c, handle))
                {
                    var localBuffer = new byte[4096];
                    var bytesRead = reader.Read(localBuffer, 0, 4096);
                    var offset = 0;
                    while (bytesRead > 0)
                    {
                        BufferHelper.CompareBuffers(data16K, offset, localBuffer, 0, bytesRead);
                        offset += bytesRead;
                        bytesRead = reader.Read(localBuffer, 0, 4096);
                    }
                }
            }
        }

        [TestCategory("SQL Server Integrated Test")]
        [TestMethod]
        public void WriteThenReadRandomSerializedDataUsingWriterStreamJIT()
        {
            var handle = new ValueHandle("testKey" + Guid.NewGuid().ToString());
            using (var c = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlKvDb"].ConnectionString))
            {
                using (var writer = new KeyValueWriterStream(c, handle))
                {
                    writer.Write(data16K, 4096 * 0, 4096);
                    writer.Write(data16K, 4096 * 1, 4096);
                    writer.Write(data16K, 4096 * 2, 4096);
                    writer.Write(data16K, 4096 * 3, 4096);
                    writer.Flush();
                }

                using (var reader = new KeyValueReaderStream(c, handle))
                {
                    var localBuffer = new byte[4096];
                    var bytesRead = reader.Read(localBuffer, 0, 4096);
                    var offset = 0;
                    while (bytesRead > 0)
                    {
                        BufferHelper.CompareBuffers(data16K, offset, localBuffer, 0, bytesRead);
                        offset += bytesRead;
                        bytesRead = reader.Read(localBuffer, 0, 4096);
                    }
                }
            }
        }
    }
}